/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "decode_interceptor_default.h"
#include "api/imageknife_api.h"

namespace ImageKnifePro {
bool DecodeInterceptorDefault::DecodeFrame(std::shared_ptr<ImageKnifeTaskInternal> task)
{
    DecodeArgs args;
    OH_ImageSourceNative *source = GetImageSource(args, task);
    if (source == nullptr) {
        return false;
    }
    if (!ConfigDecodeOption(args, task)) {
        return false;
    }

    OH_PixelmapNative *pixelmap = CreatePixelmapByAllocator(source, args.decodeOption, task);
    if (pixelmap == nullptr) {
        return false;
    }

    task->product.imageData = std::make_shared<ImageData>(pixelmap);

    Orientate(task, source);
    return true;
}

bool DecodeInterceptorDefault::DecodePixelmapList(std::shared_ptr<ImageKnifeTaskInternal> task, const DecodeArgs &args,
                                                  OH_ImageSourceNative *source)
{
    auto fileTypeInfo = task->GetFileTypeInfo();
    const uint32_t &frameCount = fileTypeInfo->frameCount;
    IMAGE_KNIFE_CHECK_RETURN(frameCount <= 1, false);
    int *delayList = fileTypeInfo->delayTimeList.get();
    if (delayList == nullptr) {
        // 如果无可用的帧时间信息，尝试重新获取
        delayList = new int[frameCount];
        Image_ErrorCode imgErrorCode = OH_ImageSourceNative_GetDelayTimeList(source, delayList, frameCount);
        if (imgErrorCode != IMAGE_SUCCESS) {
            task->EchoError("Get DelayTimeList Failed, error code: " + std::to_string(imgErrorCode));
            delete [] delayList;
            return false;
        }
    }

    OH_PixelmapNative **pixelmapList = new OH_PixelmapNative* [frameCount];
    auto imgErrorCode = OH_ImageSourceNative_CreatePixelmapList(source, args.decodeOption, pixelmapList, frameCount);
    if (imgErrorCode != IMAGE_SUCCESS) {
        task->EchoError("Create Pixelmap List Failed, error code: " + std::to_string(imgErrorCode));
        delete [] pixelmapList;
        // 如果delayList是新分配的，解码失败的情况下进行释放
        if (fileTypeInfo->delayTimeList.get() == nullptr && delayList != nullptr) {
            delete [] delayList;
        }
        if (task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
            auto request = task->GetImageKnifeRequestInternal();
            IMAGE_KNIFE_CHECK_RETURN(request == nullptr, false);
            request->GetImageInfo().errorInfo.code = LoadFailedCode::IMAGE_PIXEL_MAP_ERROR;
        }
        return false;
    }

    if (fileTypeInfo->delayTimeList.get() == nullptr) {
        task->product.imageData = std::make_shared<ImageData>(pixelmapList, delayList, frameCount);
    } else {
        task->product.imageData = std::make_shared<ImageData>(pixelmapList, fileTypeInfo->delayTimeList, frameCount);
    }

    return true;
}

OH_ImageSourceNative *DecodeInterceptorDefault::GetImageSource(DecodeArgs &args,
                                                               std::shared_ptr<ImageKnifeTaskInternal> task)
{
    OH_ImageSourceNative *source = task->GetImageSourceNative();
    if (source != nullptr) {
        return source;
    }

    // 如果没有能够复用的ImageSource，则创建一个，跟随DecodeArgs析构
    auto errorCode = OH_ImageSourceNative_CreateFromData(task->product.imageBuffer.get(),
                                                         task->product.imageLength, &source);
    if (errorCode != IMAGE_SUCCESS) {
        task->EchoError("Create ImageSource Failed, errorCode:" + std::to_string(errorCode));
        if (task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
            auto request = task->GetImageKnifeRequestInternal();
            IMAGE_KNIFE_CHECK_RETURN(request == nullptr, nullptr);
            request->GetImageInfo().errorInfo.code = LoadFailedCode::IMAGE_SOURCE_ERROR;
        }
        return nullptr;
    }
    args.source = source;
    return source;
}

OH_PixelmapNative *DecodeInterceptorDefault::CreatePixelmapByAllocator(OH_ImageSourceNative *source,
    OH_DecodingOptions *decodeOption, std::shared_ptr<ImageKnifeTaskInternal> task)
{
    auto request = task->GetImageKnifeRequestInternal();
    IMAGE_KNIFE_CHECK_RETURN(request == nullptr, nullptr);
    auto option = request->GetImageKnifeOption();
    IMAGE_KNIFE_CHECK_RETURN(option == nullptr, nullptr);

    OH_PixelmapNative *pixelmap = nullptr;
    Image_ErrorCode errCode = IMAGE_SUCCESS;

    static auto apiFunc = ImageKnifeApi::GetInstance().GetImageSourceApi().GetApiCreatePixelmapByAllocator();
    if (apiFunc != nullptr) {
        IMAGE_ALLOCATOR_TYPE allocatorType = IMAGE_ALLOCATOR_TYPE::IMAGE_ALLOCATOR_TYPE_AUTO;
        if (task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
            allocatorType = static_cast<IMAGE_ALLOCATOR_TYPE>(option->allocationMode);
        }
        errCode = apiFunc(source, decodeOption, allocatorType, &pixelmap);
        // 如果内存分配方式不支持，则使用默认分配方式解码
        if (errCode == IMAGE_SOURCE_UNSUPPORTED_ALLOCATOR_TYPE && option->allocationMode != AllocationMode::AUTO) {
            task->EchoError("Allocator Type Not Support, Use Allocation Auto mode");
            errCode = apiFunc(source, decodeOption, IMAGE_ALLOCATOR_TYPE_AUTO, &pixelmap);
        }
    } else {
        errCode = OH_ImageSourceNative_CreatePixelmap(source, decodeOption, &pixelmap);
    }

    if (errCode != IMAGE_SUCCESS) {
        task->EchoError("Create Pixelmap Failed, error code: " + std::to_string(errCode));
        if (task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
            request->GetImageInfo().errorInfo.code = LoadFailedCode::IMAGE_PIXEL_MAP_ERROR;
        }
        return nullptr;
    }

    return pixelmap;
}

IMAGE_DYNAMIC_RANGE DecodeInterceptorDefault::GetDesiredDynamicRange(std::shared_ptr<ImageKnifeTask> task)
{
    if (task->GetImageRequestType() == ImageRequestType::MAIN_SRC) {
        auto request = task->GetImageKnifeRequest();
        IMAGE_KNIFE_CHECK_RETURN(request == nullptr, IMAGE_DYNAMIC_RANGE_AUTO);
        auto option = request->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK_RETURN(option == nullptr, IMAGE_DYNAMIC_RANGE_AUTO);
        return static_cast<IMAGE_DYNAMIC_RANGE>(option->dynamicRange);
    }

    return IMAGE_DYNAMIC_RANGE_AUTO;
}

}